/*
 * HTModelNode.java
 * www.bouthier.net
 *
 * The MIT License :
 * -----------------
 * Copyright (c) 2001-2003 Christophe Bouthier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package hypertree.model;


/**
 * The HTModelNode class implements encapsulation of a HTNode for the model. It
 * keeps the original euclidian coordinates of the node. It implements the
 * Composite design pattern.
 * 
 * @author Christophe Bouthier [bouthier@loria.fr]
 * @version 1.0
 */
public class HTModelNode
{

	private HTNode					node	= null; // encapsulated
																				// HTNode

	protected HTModel				model	= null; // tree
																				// model
	protected HTModelNodeComposite	parent	= null; // parent
																				// node

	protected HTCoordE				z		= null; // Euclidian
																				// coordinates
	protected double				weight	= 1.0;	// part
																					// of
																					// space
																					// taken

	// by this node

	/* --- Constructor --- */

	/**
	 * Constructor for root node.
	 * 
	 * @param node
	 *            the encapsulated HTNode
	 * @param model
	 *            the tree model using this HTModelNode
	 */
	public HTModelNode(HTNode node, HTModel model)
	{
		this(node, null, model);
	}

	/**
	 * Constructor.
	 * 
	 * @param node
	 *            the encapsulated HTNode
	 * @param parent
	 *            the parent node
	 * @param model
	 *            the tree model using this HTModelNode
	 */
	public HTModelNode(HTNode node, HTModelNodeComposite parent, HTModel model)
	{
		this.node = node;
		this.parent = parent;
		this.model = model;
		model.incrementNumberOfNodes();

		this.z = new HTCoordE();
	}

	/* --- Encapsulated node --- */

	/**
	 * Returns the encapsulated node.
	 * 
	 * @return the encapsulated node
	 */
	public HTNode getNode()
	{
		return this.node;
	}

	/* --- Name --- */

	/**
	 * Returns the name of this node.
	 * 
	 * @return the name of this node
	 */
	public String getName()
	{
		return this.node.getName();
	}

	/* --- Weight Managment --- */

	/**
	 * Returns the weight of this node.
	 * 
	 * @return the weight of this node
	 */
	public double getWeight()
	{
		return this.weight;
	}

	/* --- Tree management --- */

	/**
	 * Returns the parent of this node.
	 * 
	 * @return the parent of this node
	 */
	public HTModelNodeComposite getParent()
	{
		return this.parent;
	}

	/**
	 * Returns <CODE>true</CODE> if this node is not an instance of
	 * HTModelNodeComposite.
	 * 
	 * @return <CODE>true</CODE>
	 */
	public boolean isLeaf()
	{
		return true;
	}

	/* --- Coordinates --- */

	/**
	 * Returns the coordinates of this node. Thoses are the original hyperbolic
	 * coordinates, without any translations. WARNING : this is NOT a copy but
	 * the true object (for performance).
	 * 
	 * @return the original hyperbolic coordinates
	 */
	public HTCoordE getCoordinates()
	{
		return this.z;
	}

	/* --- Hyperbolic layout --- */

	/**
	 * Layouts the nodes in the hyperbolic space.
	 */
	public void layoutHyperbolicTree()
	{
		HTSector sector = new HTSector();
		double eps = 0.01;
		double d = Math.sqrt(1 - (eps * eps));
		sector.A = new HTCoordE(d, eps);
		sector.B = new HTCoordE(d, -eps);
		this.layout(sector, this.model.getLength());
	}

	/**
	 * Layout this node in the hyperbolic space. First set the point at the
	 * right distance, then translate by father's coordinates. Then, compute the
	 * right angle and the right width.
	 * 
	 * @param sector
	 *            the sector
	 * @param length
	 *            the parent-child length
	 */
	public void layout(HTSector sector, double length)
	{
		// Nothing to do for the root node
		if (this.parent == null)
		{
			return;
		}

		HTCoordE zp = this.parent.getCoordinates();

		double angle = sector.getBisectAngle();

		// We first start as if the parent was the origin.
		// We still are in the hyperbolic space.
		this.z.x = length * Math.cos(angle);
		this.z.y = length * Math.sin(angle);

		// Then translate by parent's coordinates
		this.z.translate(zp);
	}

	/* --- ToString --- */

	/**
	 * Returns a string representation of the object.
	 * 
	 * @return a String representation of the object
	 */
	@Override
	public String toString()
	{
		String result = this.getName() + "\n\t" + this.z + "\n\tWeight = "
				+ this.weight;
		return result;
	}

}
